﻿#include "widget.h"
#include <QApplication>
#include <QStyleFactory>
#include <QMessageBox>
#include <QDir>
#include "application.h"
#include "utils/winmanager.h"
#include <QTextBrowser>
#include <QSplashScreen>
#include <QElapsedTimer>
#include <QDebug>
#include <QInputDialog>
#include <QAxObject>
#include <Windows.h>

#include <simple.h>
#include <BreakpadHandler.h>
#include <logger.h>

#include<QtPlugin>
//Q_IMPORT_PLUGIN(qjpeg)
//Q_IMPORT_PLUGIN(qcncodecs)
//#pragma comment(lib, "qcncodecs.lib")r

void initPath(){
    QString path = QStandardPaths::writableLocation(QStandardPaths::DataLocation)+"/data";
    QDir dir(path);
    if(!dir.exists())
        dir.mkpath(path);
    //init LibraryPath
//    QApplication::setLibraryPaths(QStringList()<<QApplication::applicationDirPath()+"/../lib"<<QApplication::applicationDirPath()+"/../plugins");
//    QString libpath = QApplication::applicationDirPath()+"/../plugins";
//    QApplication::addLibraryPath(libpath);
//    libpath = QApplication::applicationDirPath()+"/../lib";
//    QApplication::addLibraryPath(libpath);
//    qDebug()<<"libpath:"<<QApplication::libraryPaths();
}

int SingleApp(){//TODO:problem.
    int ret = 1;
    QSharedMemory sharedMemory;
    sharedMemory.setKey("FishProjectApp");
//    if (sharedMemory.create(1) && sharedMemory.error() != QSharedMemory::AlreadyExists)
    if(sharedMemory.attach())
    {
        qDebug()<<"single";
        return 0;
    }
    sharedMemory.create(1);
    qDebug()<<"create";
    return ret;
}

void setupLang()
{
    QString langName = QLocale::system().name();
    QStringList list;
    list << ":/res/lang/qtbasesubset_%1.qm"<<
            ":/res/lang/FishProject_%2.qm";
    foreach(QString fileName,list){
        QString langFile =  fileName.arg(langName);
        QFileInfo fileInfo(langFile);
        if(fileInfo.exists()){
            QTranslator *translator = new QTranslator(qApp);
            translator->load(langFile);
            qApp->installTranslator(translator);
        }
    }
}

void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QByteArray localMsg = msg.toLocal8Bit();
    QString log;
    switch(type)
    {
    case QtDebugMsg:
        log = QString("<p style='color:red;'>Debug: ");
        fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        break;
    case QtWarningMsg:
        log = QString("<p style='color:blue;'>Error: ");
        fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        break;
    case QtCriticalMsg:
        log = QString("Critical Error: ");
        fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        break;
    case QtFatalMsg:
        log = QString("Fatal Error: ");
        fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        abort();
    default:
        log = QString("Unknow Msg Type : ");
        break;
    };
    log += QTime::currentTime().toString("hh:mm:ss.zzz, File: ") + QString(context.file) ;
    log += QString(", Line: " ) + QString::number(context.line) + QString(" : %1\n").arg(msg);
    log += "<\p>";

    Application::appendDebugMsg(log);
}

void myMessageOutputCust(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QByteArray localMsg = msg.toLocal8Bit();
    switch (type) {
    case QtDebugMsg:
        fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
//        fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        break;
    case QtWarningMsg:
        fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        break;
    case QtCriticalMsg:
        fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        break;
    case QtFatalMsg:
        fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
        abort();
    }
}

void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QString log;

    switch (type) {
    case QtDebugMsg:
        log = QString("<p style='color:red;'>Debug: ");
        Simple::Logger::debug(QString("%1 (%2:%3, %4)").arg(msg).arg(context.file).arg(context.line).arg(context.function));
        break;
    case QtWarningMsg:
        log = QString("<p style='color:blue;'>Error: ");
        Simple::Logger::warn(QString("%1 (%2:%3, %4)").arg(msg).arg(context.file).arg(context.line).arg(context.function));
        break;
    case QtCriticalMsg:
        log = QString("Critical Error: ");
        Simple::Logger::error(QString("%1 (%2:%3, %4)").arg(msg).arg(context.file).arg(context.line).arg(context.function));
        break;
    case QtFatalMsg:
        log = QString("Fatal Error: ");
        Simple::Logger::fatal(QString("%1 (%2:%3, %4)").arg(msg).arg(context.file).arg(context.line).arg(context.function));
        //fprintf(stderr, "Fatal: %s\n", msg);
        //abort();
        break;
    }

    log += QTime::currentTime().toString("hh:mm:ss.zzz, File: ") + QString(context.file) ;
    log += QString(", Line: " ) + QString::number(context.line) + QString(" : %1\n").arg(msg);
    log += "<\p>";
//    Application::appendDebugMsg(log);
}

QString getWMIHWInfo(int type){
    /*
//0.当前原生网卡地址：
SELECT MACAddress FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))
// 1.硬盘序列号
SELECT PNPDeviceID FROM Win32_DiskDrive WHERE(SerialNumber IS NOT NULL) AND (MediaType LIKE 'Fixed hard disk%')
//2.获取主板序列号
SELECT SerialNumber FROM Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)
// 3.处理器ID
SELECT ProcessorId FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)
// 4.BIOS序列号
SELECT SerialNumber FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)
// 5.主板型号
SELECT Product FROM Win32_BaseBoard WHERE (Product IS NOT NULL)*/
    QString hwInfo=QString("");
    QStringList sqlCmd;
    sqlCmd.clear();
    sqlCmd<<QString("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))");
    //注意qt调用 wmi时，对查询语句要求很严格，所以 like之类的句子务必精确才能有结果出来
    sqlCmd<<QString("SELECT PNPDeviceID FROM Win32_DiskDrive WHERE( PNPDeviceID IS NOT NULL) AND (MediaType LIKE 'Fixed%')");
    sqlCmd<<QString("SELECT SerialNumber FROM Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)");
    sqlCmd<<QString("SELECT ProcessorId FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)");
    sqlCmd<<QString("SELECT SerialNumber FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)");
    sqlCmd<<QString("SELECT Product FROM Win32_BaseBoard WHERE (Product IS NOT NULL)");
    QStringList columnName;
    columnName.clear();
    columnName<<QString("MACAddress");
    columnName<<QString("PNPDeviceID");
    columnName<<QString("SerialNumber");
    columnName<<QString("ProcessorId");
    columnName<<QString("SerialNumber");
    columnName<<QString("Product");
    QAxObject *objIWbemLocator = new QAxObject("WbemScripting.SWbemLocator");
    QAxObject *objWMIService = objIWbemLocator->querySubObject("ConnectServer(QString&,QString&)",QString("."),QString("root\\cimv2"));
    QString query=QString("");
    if(type<sqlCmd.size())
        query=sqlCmd.at(type);
    QAxObject *objInterList = objWMIService->querySubObject("ExecQuery(QString&))", query);
    QAxObject *enum1 = objInterList->querySubObject("_NewEnum");
    //需要 include windows.h
    IEnumVARIANT* enumInterface = 0;
//    qDebug()<<QUuid((GUID)IID_IEnumVARIANT);
    enum1->queryInterface(QUuid((GUID)IID_IEnumVARIANT), (void**)&enumInterface);
    enumInterface->Reset();
    for (int i = 0; i < objInterList->dynamicCall("Count").toInt(); i++) {
        VARIANT *theItem = (VARIANT*)malloc(sizeof(VARIANT));
        if (enumInterface->Next(1,theItem,NULL) != S_FALSE){
            QAxObject *item = new QAxObject((IUnknown *)theItem->punkVal);
            if(item){
                if(type<columnName.size()){
                    QByteArray datagram(columnName.at(type).toLatin1()); //Or
                    const char* tempConstChar = datagram.data();
                    qDebug()<<"the query is "<<query<<" and cn is "<<QString::fromLatin1(tempConstChar);
                    hwInfo=item->dynamicCall(tempConstChar).toString();
                }
                qDebug() <<" string is "<<hwInfo;
            }else{
                qDebug() <<" item is null";
            }
        }else{
            qDebug() <<" item is false";
        }
    }
    return hwInfo;
}

QString calActiveCode(QString machineCode,int validays,QString username,QString startDate){
    QString cusinfo(QString((username.isEmpty()?"@@@ihepweiqunApplication":"@@@ihepweiqunApplication"+username) + "@@@%1@@@%2").arg(
                        QString::number(validays),startDate
                        ));
    QString originalStr120= QStringLiteral("@@@")+machineCode+cusinfo;
    QCryptographicHash sha1(QCryptographicHash::Sha1);
    QByteArray datagram(originalStr120.toLatin1());
    const char* tempConstChar = datagram.data();
    sha1.addData(tempConstChar);
    QString activeCode=sha1.result().toHex();
    return activeCode;
}

QString GetCustCodeOfFeeder(QString data1,/*start day*/QString data2/*cal days*/,QString data3/*user name*/)
{
    QString code("");
    QString maccode(getWMIHWInfo(2));
    code.append(maccode);
    int days = data2.toInt();
    //格式：机器码    使用天数    激活日期    用户名
    code = calActiveCode(code,days,data3,data1);
    return code;
}

bool activation(){
    QSettings reg(QString("HKEY_CURRENT_USER\\Software\\Active\\%1").arg(qApp->applicationName()),QSettings::NativeFormat);
    QString activeCode = reg.value("activeCode").toString();

    QString startdate,caldate,username;
    QByteArray plaintext = reg.value("activeInfo").toByteArray();
    QBuffer buffer(&plaintext);
    buffer.open(QIODevice::ReadOnly);
    QDataStream s(&buffer);
    s.setVersion(QDataStream::Qt_5_2);
    s >> caldate; //stream in a string
    s >> startdate;
    s >> username;
    buffer.close();

    if(activeCode.isEmpty() || plaintext.isEmpty())
        return false;

    //超过时间
    QDate date(startdate.left(4).toInt(),startdate.mid(4,2).toInt(),startdate.right(2).toInt());
    int days = date.daysTo(QDate::currentDate());
    qDebug()<<date<<days;
    if(days+1>caldate.toInt())
        return false;

    QString custcode = GetCustCodeOfFeeder(startdate,caldate,username);
    if(custcode != activeCode)
        return false;

    return true;
}

int main(int argc, char *argv[])
{
    //for static.
//    Q_INIT_RESOURCE(Res);
//    Q_INIT_RESOURCE(icons);

    Application application(argc, argv);

    if(!activation()){
        QMessageBox::about(0,"",QStringLiteral("软件已超使用期，请联系管理员进行注册"));
        return 0;
    }

    QPixmap pixmap(QApplication::applicationDirPath() + QDir::separator() + "screen.jpg");
    pixmap = pixmap.scaled(800,450);
//    qDebug()<<pixmap.isNull()<<QApplication::applicationDirPath() + QDir::separator() + "screen.png";
    QSplashScreen screen(pixmap);
    screen.show();
    screen.showMessage("loading...", Qt::AlignCenter, Qt::white);


    //! install message log
//    qInstallMessageHandler(myMessageOutput);
//    qInstallMessageHandler(myMessageOutputCust);
    {//! [1] new way to record debug message.
    QString logdir = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QDir::separator() + "debug" + QDir::separator() +"log";
    QString crashdir = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QDir::separator() + "debug" + QDir::separator() + "crash";
    QDir dirlog(logdir);
    if(!dirlog.exists())
        dirlog.mkpath(logdir);
    Simple::Logger::setup(Simple::Logger::TraceLevel,true,1024*1024,6, dirlog.absoluteFilePath("log.txt"));
    qInstallMessageHandler(messageOutput);
    dirlog = QDir(crashdir);
    if(!dirlog.exists())
        dirlog.mkpath(crashdir);
    BreakpadQt::GlobalHandler::instance()->setDumpPath(dirlog.absolutePath());
    }//! [1]

    //! end
//    QString dir = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
//    dir = QString("%1/%2/%3").arg(dir).arg("data").arg("crashes");
    initPath();

    ///启动画面
#if 0
    int delayTime = 5;
    QElapsedTimer timer;
    timer.start();
    while(timer.elapsed() < (delayTime * 1000))
    {
         application.processEvents();
    }
#endif

#if 1
    QDateTime n=QDateTime::currentDateTime();
    QDateTime now;
//    QStringList listload = QStringList()<<"."<<".."<<"...";
//    int i = 0;
    do{
//        if(i >= listload.count())
//            i = 0;
        now=QDateTime::currentDateTime();
        application.processEvents();
//        if((int)(n.msecsTo(now)*0.01)%3 == i){
//            screen.showMessage(QString("loading%1").arg(listload.at(i++)), Qt::AlignCenter, Qt::white);
//        qDebug()<<"...:"<<(int)(n.msecsTo(now)*0.01)%2;
//        }
    } while (n.secsTo(now)<=3);
#endif

//    Widget w1;

    if (!application.isTheOnly() || !application.isCorrectlyInitialized()){
//        if(&w1)
//            if(w1.isHidden()){
//                w1.showNormal();
//                w1.activateWindow();
//            }
        return 0;
    }
//    else{
        WinMgr.showMain();
        Application::GetDebugBrowser()->move(WinMgr.getMain()->pos() + QPoint(WinMgr.getMain()->width() + 15 ,0));
//    }

    screen.finish(WinMgr.getMain());
    return application.exec();

    //create by vacant.
    //! [use the custom Application QCore.]
    //.....end

    QSystemSemaphore sema("UniqueFishPro",1,QSystemSemaphore::Open);
    sema.acquire();
    QSharedMemory mem("SystemObject");
    if (!mem.create(1))
    {
        sema.release();
        QApplication::activeWindow();
        return 0;
    }
    sema.release();

    QApplication a(argc, argv);
    a.setOrganizationName("YanboOrg");
    a.setApplicationName("FishSoftware");

    setupLang();//设置语言

    QApplication::setStyle(QStyleFactory::create("Fusion"));

    Widget w;
    w.setWindowFlags(w.windowFlags()& ~Qt::WindowMaximizeButtonHint);
    //! [0]
    //Yanbo Tcp class Define and handle:TCP连接类处理方法
    ////1 槽
    //connect(/*你定义的TCP连接类对象*/,SIGNAL(/*对应的信号*/),&w,SLOT(finishedConnectSlot(int,bool)));//连接成功返回对应组号连接状态
    //connect(/*你定义的TCP连接类对象*/,SIGNAL(/*对应的信号*/),&w,SLOT(finishedPutWeigh(int,send_head)));//称量成功后返回实际称量对应槽处理函数
    ////1 信号处理
    ////    void sendConnectSocket(QMap<int,QString>);//点击“发送”按钮,触发信号,发送组号及对应IP
    ////    void sendGroupPutWeighInfo(int,send_head);//发送称量信息-以得到返回称量并进行UI交互
    ////    void sendGroupBatchInfo(int,send_head);//发送投料信息-以进行最后实际处理-TCP接收站信号后发送数据到硬件进行处理
    ////    void closeConnect();//断开连接信号
    //connect(&w,SIGNAL(sendConnectSocket(QMap<int,QString>)),/*你定义的TCP连接类对象*/,SIGNAL/SLOT(/*对应的信号 或 槽处理函数*/));
    //connect(&w,SIGNAL(sendGroupPutWeighInfo(int,send_head)),/*你定义的TCP连接类对象*/,SIGNAL/SLOT(/*对应的信号 或 槽处理函数*/));
    //connect(&w,SIGNAL(sendGroupBatchInfo(int,send_head)),/*你定义的TCP连接类对象*/,SIGNAL/SLOT(/*对应的信号 或 槽处理函数*/));
    //connect(&w,SIGNAL(closeConnect()),/*你定义的TCP连接类对象*/,SIGNAL/SLOT(/*对应的信号 或 槽处理函数*/));
    //! [0]-end!
    w.show();
    return a.exec();
}
